package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.UnknownFormatConversionException;

/**
 * 全局过滤器
 *  *     校验是否登录
 *  *      自定义过滤器 GlobalLoginFilter
 *  *      默认执行 9大过滤器
 *  *      10大过滤器    1 2 3 4 5 6 7 8 9 10
 */
@Component
public class GlobalLoginFilter implements GlobalFilter, Ordered {


    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Resource
    private RedisTemplate redisTemplate;
    @Value("${auth.url}")
    private String[] authUrl;
    private static final String LOGINURL = "http://passport.gmall.com/login.html?originUrl=";

    //全局过滤器执行方法
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //1、判断当前    uri/url:http://gmall.com/list   path:/list
        String path = request.getURI().getPath();
        //2、内部资源不允许浏览器访问   /**/inner/**
        if (antPathMatcher.match("/**/inner/**",path)) {//为内部资源
            return getVoidMono(response,ResultCodeEnum.PERMISSION);

        }
        //3、判断当前uri是否需要登录 /auth开始需要登录
        String userId = getUserId(request);
        //加购物车
        //3.1、弹窗：异步 /**/auth/**  token存header头     ajax 不刷新页面
        //带auth使用异步登录
        if (antPathMatcher.match("/**/auth/**",path)){//需要登录
            if (StringUtils.isEmpty(userId)){
                return getVoidMono(response,ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //3.2、转发：同步 trade.html/order.html/pay.html token存cookie     路由到后面页面微服务 window.location.href
        //访问上三个页面使用同步登录
        for (String url : authUrl){
            if (path.indexOf(url) != -1 && StringUtils.isEmpty(userId)){
                response.setStatusCode(HttpStatus.SEE_OTHER);
                //URL地址
                try {
                    response.getHeaders().set(HttpHeaders.LOCATION,
                            LOGINURL + URLEncoder.encode(request.getURI().toString(),"utf-8")
                    );
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return response.setComplete();//完成之后可以响应了
            }
        }
        //加入购物车
        //当前是网关 传递用户ID给后面的微服务   请求头 K:userId V:3
        //request.getHeaders().set("userId",userId);
        if (!StringUtils.isEmpty(userId)) {//若首页无需登录，不用传递userID浪费性能
            request.mutate().header("userId", userId);
        }
        //2）传递临时用户ID
        String userTempId = getUserTempId(request);
        if(!StringUtils.isEmpty(userTempId)){
            request.mutate().header("userTempId", userTempId);
        }

        return chain.filter(exchange);
    }

    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = request.getHeaders().getFirst("userTempId");
        if (StringUtils.isEmpty(userTempId)){
            HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
            if (httpCookie != null){
                userTempId = httpCookie.getValue();
            }
        }
        return userTempId;
    }

    private Mono<Void> getVoidMono(ServerHttpResponse response,ResultCodeEnum resultCodeEnum) {
        Result<Object> r = Result.build(null, resultCodeEnum);
        String result = JSONObject.toJSONString(r);//前后端互通使用ajax，json传输
        DataBuffer dataBuffer = response.bufferFactory().wrap(result.getBytes());
        //解决乱码
        response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        //返回mono对象  response.bufferFactory().wrap(result.getBytes());    response.writeWith(Mono.just(dataBuffer))
        return response.writeWith(Mono.just(dataBuffer));
    }

    private String getUserId(ServerHttpRequest request){
        //1、获取命令(区分同/异步的token)    获取异步token if中获取同步token
        String token = request.getHeaders().getFirst("token");
        if (StringUtils.isEmpty(token)){//空，不在头内，非异步(同步+空)
            HttpCookie httpCookies = request.getCookies().getFirst("token");
            if (httpCookies != null){//同步，已排除空情况
                token = httpCookies.getValue();
            }
        }
        //
        //2、缓存中查询是否存在用户id   有：登录    无：未登录
        if (!StringUtils.isEmpty(token)){
            if (redisTemplate.hasKey(token)){
                return (String) redisTemplate.opsForValue().get(token);//缓存中根据token获取用户id
            }
        }
        //3、无 无法获取token/redis中无对应token --> 1、if-if-else     2、if-if-else
        return null;
    }

    //过滤器执行顺序   负整数最大值  0   正整数最大值
    @Override
    public int getOrder() {
        return 0;
    }
}
